package com.ctw.tinyservices.id.server.segment.dao.impl;

import com.ctw.tinyservices.id.common.entity.IdSegment;
import com.ctw.tinyservices.id.common.utils.LogUtils;
import com.ctw.tinyservices.id.server.segment.dao.IdSegmentDAO;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * @author TongWei.Chen 2022/3/3 13:34
 *
 * Id号段DAO具体实现
 **/
public class IdSegmentDAOImpl implements IdSegmentDAO {
    private JdbcTemplate jdbcTemplate;
    private DataSourceTransactionManager transactionManager;

    public IdSegmentDAOImpl(JdbcTemplate jdbcTemplate, DataSourceTransactionManager transactionManager) {
        this.jdbcTemplate = jdbcTemplate;
        this.transactionManager = transactionManager;
    }

    @Override
    public List<IdSegment> getByBizTypeAndNotInit(String bizType) {
        return jdbcTemplate.query("SELECT id, biz_type, begin_id, max_id, step, create_time, update_time FROM ts_id_segment WHERE biz_type = ? AND is_need_init = 0", new Object[]{bizType}, new IdSegmentRowMapper());
    }

    @Override
    public IdSegment updateMaxIdAndGet(String bizType) {
        LogUtils.info(IdSegmentDAOImpl.class, "[updateMaxIdAndGet] method begin, bizType is [{}]", bizType);
        TransactionStatus status = null;
        IdSegment idSegment;
        try {
            status = begin();
            jdbcTemplate.update("UPDATE ts_id_segment SET max_id = max_id + step WHERE biz_type = ?", new Object[]{bizType});
            idSegment = jdbcTemplate.queryForObject("SELECT id, biz_type, begin_id, max_id, step, create_time, update_time FROM ts_id_segment WHERE biz_type = ?", new Object[]{bizType}, new IdSegmentRowMapper());
            commit(status);
            return idSegment;
        } catch (Exception e) {
            LogUtils.error(IdSegmentDAOImpl.class, "[updateMaxIdAndGet] method error and transaction rollback, bizType is [{}]", bizType, e);
            rollback(status);
            throw e;
        }
    }

    @Override
    public IdSegment updateMaxIdByStepAndGet(String bizType, int step) {
        LogUtils.info(IdSegmentDAOImpl.class, "[updateMaxIdByStepAndGet] method begin, bizType is [{}]", bizType);
        TransactionStatus status = null;
        IdSegment idSegment;
        try {
            status = begin();
            jdbcTemplate.update("UPDATE ts_id_segment SET max_id = max_id + ? WHERE biz_type = ?", new Object[]{step, bizType});
            idSegment = jdbcTemplate.queryForObject("SELECT id, biz_type, begin_id, max_id, step, create_time, update_time FROM ts_id_segment WHERE biz_type = ?", new Object[]{bizType}, new IdSegmentRowMapper());
            commit(status);
            return idSegment;
        } catch (Exception e) {
            LogUtils.error(IdSegmentDAOImpl.class, "[updateMaxIdByStepAndGet] method error and transaction rollback, bizType is [{}]", bizType, e);
            rollback(status);
            throw e;
        }
    }

    @Override
    public List<IdSegment> list() {
        return jdbcTemplate.query("SELECT id, biz_type, begin_id, max_id, step, create_time, update_time FROM ts_id_segment WHERE is_need_init = 1", new IdSegmentRowMapper());
    }

    /**
     * 开启事务
     */
    public TransactionStatus begin(){
        return beginTransaction(transactionManager);
    }


    /**
     * 提交事务
     * @param status
     */
    public void commit(TransactionStatus status){
        commitTransaction(transactionManager,status);
    }

    /**
     * 回滚事务
     * @param status
     */
    public void rollback(TransactionStatus status){
        rollbackTransaction(transactionManager,status);
    }

    /**
     * 开启事务
     */
    public TransactionStatus beginTransaction(DataSourceTransactionManager transactionManager){
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        return transactionManager.getTransaction(def);
    }

    /**
     * 提交事务
     * @param transactionManager
     * @param status
     */
    public void commitTransaction(DataSourceTransactionManager transactionManager,TransactionStatus status){
        transactionManager.commit(status);
    }

    /**
     * 事务回滚
     * @param transactionManager
     * @param status
     */
    public void rollbackTransaction(DataSourceTransactionManager transactionManager,TransactionStatus status){
        transactionManager.rollback(status);
    }

    private static class IdSegmentRowMapper implements RowMapper<IdSegment> {
        @Override
        public IdSegment mapRow(ResultSet resultSet, int i) throws SQLException {
            IdSegment idSegment = new IdSegment();
            idSegment.setId(resultSet.getLong("id"));
            idSegment.setBizType(resultSet.getString("biz_type"));
            idSegment.setBeginId(resultSet.getLong("begin_id"));
            idSegment.setMaxId(resultSet.getLong("max_id"));
            idSegment.setStep(resultSet.getInt("step"));
            idSegment.setCreateTime(resultSet.getDate("create_time"));
            idSegment.setUpdateTime(resultSet.getDate("update_time"));
            return idSegment;
        }
    }

}
